1. 问题
年老代报警:内存占用95%以上,持续1分钟以上,只能重启tomcat server
语义报警:连续3次,间隔10秒,服务器没有响应
2. 信息收集
访问日志:$TOMCAT_HOME/log/localhost_access_log.txt
gc日志:$TOMCAT_HOME/log/gc.log
应用日志:
heapdump:报警时收集
3. 分析与定位
3.1 访问日志分析
问题时间段内 耗时60秒以上的url大部分都是/client/account/overview/accountReport!reportJson.action
查看Struts配置,对应的Action类和方法是com.baidu.union.report.InitAccountReportAction.reportJson()
3.2 gc日志分析
![image-20201028095230949](/Users/hepeitan/Library/Application Support/typora-user-images/image-20201028095230949.png)
年老代无法回收,频繁发生CMS收集,被minor gc打断发生concurrent mode failure,转为串行收集。
初步结论:结合3.1、3.2占用内存较大的方法必然执行时间很长,是InitAccountReportAction.reportJson()导致了问题
3.3 heapdump分析
两个较大对象:ArrayList和byte[],ArrayList的详细类型展开可以看到ArrayList<HashMap<String, Long>>
3.4 应用日志
===============response head from doris======================================
ActualRecNum: 1385308800
TotalNum: 0
RecordSize: 187
StatusCode: 0
=================response head from doris====================================
ActualRecNum: 1385308800 这个返回数据量明显有问题
查看错误信息:
[work@yf-cloud04root]$ more root.log.2013-12-11-18|grep Exception
java.net.SocketException:Socket is closed
java.net.SocketException:Socket closed
java.net.SocketException:Broken pipe
貌似是多线程的问题,并发线程共享一个socket导致。
3.5 查看代码
根据3.3、3.4,问题可能出现在doris访问上,查看doris代码,getDortisData方法返回值ArrayList与Heapdump中4G对象相同
获取doris返回数据代码
构造java对象代码
unionweb的doris客户端会根据返回数据的字节码位置解析返回数据大小、业务数据等信息,如果两个线程共享一个socket,
就会出现返回数据解析错误,比如ActualRecNum: 1385308800,这种问题。
3.6 多线程问题分析
首先查看socket连接池的获取、回收方法,没有问题。
union-web使用SSH,经典的Action-Serivce-Dao三层结构,spring默认使用singliton管理bean,三层中有一个bean是共享的都可能导致这个问题。
使用btrace调试代码,发现问题发生在Service层,对象地址一样说明是同一个对象
3.7 其他问题
记录调试日志发现socket连接池可用连接一直是0,但是active却能达到max 100,
调试发现这段代码有问题
com.baidu.darwin.doris.driver.SocketDriver中
结合配置文件,代码中缺少正确创建socket跳出的机制,每次调用都会产生一个无法返回pool的socket
最终Pool通过_numActive计数到达max,但是仅有一个socket可用
4. 修复问题
4.1 修改spring关于*Mgr *Dao的配置,添加注解,scope改为prototype
4.2 修改代码,socket正确创建则跳出循环